/*
 * Rotate writed by instaruction from
 * http://blog.wolfire.com/2010/07/Linear-algebra-for-game-developers-part-4
 * 
 * writed by Alexey Matveev (AlMat26)
*/


#include <GLES3/gl3.h>

#include <mesh/mesh.h>
#include <app/modules/thirdParty/OBJLoader.h>


enum MeshBufferPositions {
    POSITION_VB,
    TEXCOORD_VB,
	NORMAL_VB,
	INDEX_VB
};

Vertex::Vertex ( glm::vec3 position, glm::vec2 textureCoordinates, glm::vec3 normal ) {
    
    this -> position = position;
    this -> textureCoordinates = textureCoordinates;
    this -> normal = normal;
}

glm::vec3* Vertex::getPosition () {
    
    return &this -> position;
}

glm::vec2* Vertex::getTextureCoordinates () {
    
    return &this -> textureCoordinates;
}

glm::vec3* Vertex::getNormal () {
    
    return &this -> normal;
}


Mesh::Mesh ( Vertex* vertices, unsigned int verticesCount, unsigned int* indices, unsigned int indicesCount ) {
    
    Model model;
    
    for ( unsigned int i = 0; i < verticesCount; i++ ) {
        
        model.positions.push_back ( *vertices [i].getPosition () );
        model.textureCoordinates.push_back ( *vertices [i].getTextureCoordinates () );
        model.normals.push_back ( *vertices [i].getNormal () );
    }
    
    for(unsigned int i = 0; i < indicesCount; i++) {
        
        model.indices.push_back ( indices [i] );
    }
    
    InitMesh ( model );
}

Mesh::Mesh ( std::string filename ) {
    InitMesh ( OBJModel ( filename ).ToIndexedModel () );
}


void Mesh::InitMesh ( const Model& model) {
    m_numIndices = model.indices.size();

    glGenVertexArrays ( 1, &m_vertexArrayObject );
    glBindVertexArray ( m_vertexArrayObject );

    glGenBuffers( BUFFERS_COUNT, m_vertexArrayBuffers );

    glBindBuffer ( GL_ARRAY_BUFFER, m_vertexArrayBuffers [ POSITION_VB ] );
    glBufferData ( GL_ARRAY_BUFFER, sizeof ( model.positions [0] ) * model.positions.size (), &model.positions [0], GL_STATIC_DRAW );
    glEnableVertexAttribArray ( 0 );
    glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, 0 );

    glBindBuffer ( GL_ARRAY_BUFFER, m_vertexArrayBuffers [ TEXCOORD_VB ] );
    glBufferData ( GL_ARRAY_BUFFER, sizeof ( model.textureCoordinates [0] ) * model.textureCoordinates.size (), &model.textureCoordinates [0], GL_STATIC_DRAW );
    glEnableVertexAttribArray ( 1 );
    glVertexAttribPointer ( 1, 2, GL_FLOAT, GL_FALSE, 0, 0 );

    glBindBuffer ( GL_ARRAY_BUFFER, m_vertexArrayBuffers [ NORMAL_VB ]);
    glBufferData ( GL_ARRAY_BUFFER, sizeof ( model.normals [0] ) * model.normals.size (), &model.normals [0], GL_STATIC_DRAW );
    glEnableVertexAttribArray ( 2 );
    glVertexAttribPointer ( 2, 3, GL_FLOAT, GL_FALSE, 0, 0 );

    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, m_vertexArrayBuffers [ INDEX_VB ] );
    glBufferData ( GL_ELEMENT_ARRAY_BUFFER, sizeof ( model.indices [0] ) * model.indices.size (), &model.indices [0], GL_STATIC_DRAW);

    glBindVertexArray ( 0 );
}

void Mesh::Draw () {
    
    glBindVertexArray ( m_vertexArrayObject );

	glDrawElements ( GL_TRIANGLES, m_numIndices, GL_UNSIGNED_INT, 0 );
    //glDrawElementsBaseVertex ( GL_TRIANGLES, m_numIndices, GL_UNSIGNED_INT, 0, 0 );

    glBindVertexArray ( 0 );
}

Mesh::~Mesh () {
    
    glDeleteBuffers ( BUFFERS_COUNT, m_vertexArrayBuffers );
    glDeleteVertexArrays ( 1, &m_vertexArrayObject );
}
